import {
  g3x_defineClassProperties,
  plainObjectToJSON,
  jsonToPlainObject,
  registers
} from "@g3x/utils";

export default function(Ctor) {

  Ctor.plainObjectToJSON = plainObjectToJSON;
  Ctor.jsonToPlainObject = jsonToPlainObject;
  Ctor.registerProperty = registers.registerProperty;
  Ctor.registerArrayProperty = registers.registerArrayProperty;
  Ctor.registerPosition = registers.registerPosition;
  Ctor.registerRotation = registers.registerRotation;
  // Ctor.registerPathAttachedGuid = _registerPathAttachedGuid2.default;

  g3x_defineClassProperties(Ctor, [{
    key: 'xbsjFromJSON',

    /**
     * 通过JSON数据对象来设置属性
     * @param {*} jsonObject
     * @example
     * // 创建一个pin对象
     * const objConfig = {
     *     "name": 'Pin1',
     *     "xbsjType": "Pin",
     *     "position": [1.9017005694855162, 0.5972477268978722, 488.7695178987821],
     *     "near": 300,
     *     "show": false,
     *     evalString,
     * };
     * const pin = new XE.Obj.Pin(earth);
     * pin.xbsjFromJSON(objConfig);
     */
    value: function xbsjFromJSON(jsonObject) {
      // runInAction(() => {
      jsonObject = { ...this._defaultOptions, ...jsonObject};
      Ctor.jsonToPlainObject(jsonObject, this, this._fromJsonFilterKeys);
      // });
    }

    /**
     * 转化成一个JSON数据对象 <br/>
     * 注意：每次都会创建一个新对象！
     * @method
     * @returns {object} 创建的JSON数据对象
     */

  }, {
    key: 'toJSON',
    value: function toJSON(key) {
      var filterKeys = this._toJsonFilterKeys;
      var defaultOptions = this.ignoreDefualt ? this._defaultOptions : undefined;
      return Ctor.plainObjectToJSON(this, {
        defaultOptions: defaultOptions,
        filterKeys: filterKeys,
        ignoreDefualt: this.ignoreDefualt
      });
    }

    /**
     * 数据整个JSOn对象，包括默认值
     * @method
     * @returns {object} 创建的JSON数据对象
     */

  }, {
    key: 'toAllJSON',
    value: function toAllJSON(key) {
      var originIgnoreDefault = this.ignoreDefualt;
      this.ignoreDefualt = false;
      var result = this.toJSON(key);
      this.ignoreDefualt = originIgnoreDefault;
      return result;
    }

    /**
     * 转化成JSON字符串，默认元素不输出
     * @method
     * @returns {string} JSON格式化好的字符串
     */

  }, {
    key: 'toJSONStr',
    value: function toJSONStr() {
      return JSON.stringify(this, undefined, '    ');
    }

    /**
     * 转化成JSON字符串，输出全部元素
     * @method
     * @returns {string} JSON格式化好的字符串
     */

  }, {
    key: 'toAllJSONStr',
    value: function toAllJSONStr() {
      return JSON.stringify(this.toAllJSON(), undefined, '    ');
    }
    /**
     * 检查对象是否已被销毁<br/>
     * 警告：对象一旦销毁不可再次使用！仅此函数可以调用！<br/>
     * @instance
     * @returns {boolean} 对象是否已销毁
     */
  }, {
    key: 'isDestroyed',
    value: function isDestroyed() {
      return false;
    }
    /**
     * 销毁对象<br/>
     * 警告：对象一旦销毁不可再次使用！<br/>
     * 警告：挂在场景树上的对象禁止调用destroy方法，只要通过数组函数将其从场景树中移除，就会自动销毁！<br/>
     * @instance
     * @returns {undefined} 返回undefined
     * @example
     * // 使用范例
     * // 这样写的好处是，一旦对象销毁，会同时将引用该对象的变量同时置为undefined，防止再次使用。
     * this._myObject = this._myObject && this._myObject.destroy();
     */
  }, {
    key: 'destroy',
    value: function destroy() {
      this._isDestroying = true;

      this._disposers.reverse();
      this._disposers.forEach(function(d) {
        return d();
      });
      this._disposers.length = 0;

      return Cesium.destroyObject(this);
    }
  }, {
    key: 'fromJsonFilterKeys',
    get: function get() {
      return this._fromJsonFilterKeys;
    }
  }, {
    key: 'toJsonFilterKeys',
    get: function get() {
      return this._toJsonFilterKeys;
    }
  }, {
    key: '_jsonSchema',
    get: function get() {
      if (!this.constructor.schema) {
        throw new Error('需要为类定义xbsjSchema属性！');
      }

      return this.constructor.schema;
    }
  }, {
    key: '_classification',
    get: function get() {
      if (!this.constructor.classification) {
        throw new Error('需要为类定义xbsjClassification属性！');
      }

      return this.constructor.classification;
    }
  }, {
    key: '_defaultOptions',
    get: function get() {
      // defaultOptionsAccum相当于把所有基类的defaultOptions也合并进来了
      // 另外子类的同名属性的优先级更高。
      if (!this.constructor.defaultOptionsAccum || this.constructor.defaultOptionsAccum === this
        .constructor.__proto__.defaultOptionsAccum) {
        // 修复派生类不能定义defaultOptions的问题，defaultOptionsAccum会被自动集成。。。
        // 先获取所有基类
        var doOwners = [];
        var currentProto = this.__proto__;

        while (currentProto.constructor !== Ctor) {
          doOwners.push(currentProto.constructor);
          currentProto = currentProto['__proto__'];
        }

        if (currentProto.constructor !== Ctor) {
          throw new Error('currentProto迭代后必须为G3xObjBase！');
        }
        doOwners.push(currentProto.constructor);

        doOwners.reverse();

        var defaultOptions = {};
        doOwners.forEach((owner) => {
          owner.defaultOptions && Object.assign(defaultOptions,owner.defaultOptions);
        });

        this.constructor.defaultOptionsAccum = defaultOptions;
      }

      return this.constructor.defaultOptionsAccum;
    }

    /**
     * 用来收集资源销毁函数，并在析构时自动调用！
     * @example
     * // 示例1：
     * myObject.disposers.push(() => {
     *     // 此处执行需要销毁的资源
     * });
     *
     * // 示例2：
     * // XE.MVVM.bind的返回值是一个函数，作用是用来解除双向绑定，
     * // 把它的返回值放到disposer中，那么对象销毁时就会执行解绑操作。
     * myObject.disposers.push(XE.MVVM.bind(xxx));
     *
     * // 示例3：
     * // XE.MVVM.watch的返回值是一个函数，作用是用来取消监视，
     * // 把它的返回值放到disposer中，那么对象销毁时就会执行取消监视的操作。
     * myObject.disposers.push(XE.MVVM.watch(xxx));
     */

  }, {
    key: 'disposers',
    get: function get() {
      return this._disposers;
    }
  }]);
}
